using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Action.SPI;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Client;

namespace T.FAS.Runtime.Action.Service
{
    /// <summary>
    /// 运行时获取各类元数据服务
    /// </summary>
    public class MetadataRTPService
    {
        static readonly object lockobj = new object();
        static MetadataRTPService instance = null;
        public static MetadataRTPService GetInstance()
        {
            if (instance == null)
            {
                lock (lockobj)
                {
                    if (instance == null)
                        instance = new MetadataRTPService();
                }
            }
            return instance;
        }
        private MetadataRTPService()
        {
        }
        public FASMetaData GetMetadata(string metadataId, SPI.ActionType actionType,bool isMatchMetadataByCode =false)
        {
            return GetMetadataByIDOrCodeFromCache(metadataId);
        }

        public FASMetaData GetMetadataByIDOrCodeFromCache(string metadataId)
        {
            var metadata = MetaDataClientService.GetInstance().GetMetaData(metadataId);
            if (metadata == null)
                throw new FasException(ActionExecuteExceptionCode.ActionMetaDataNotExistError,string.Format(CommonStringClassService.MetadataRTPService_GetMetadataByIDOrCodeFromCache,metadataId));
            var fasMetaData = new FASMetaData();
            fasMetaData.MetaDataContent = metadata.Content;
            fasMetaData.MetaDataID = metadataId;
            fasMetaData.MetaDataCode = metadata.Code;
            if (metadata.MetaDataManageInfos != null && metadata.MetaDataManageInfos.Count > 0)
                fasMetaData.AppID = metadata.MetaDataManageInfos[0].KeyAppName;
            return fasMetaData;
        }
        public IMetaDataContent GetMetadataByCode(string metaDataCode, string metaDataType)
        {
            var metadata = MetaDataClientService.GetInstance().GetMetaDataByCode(metaDataCode, metaDataType);
            if (metadata != null)
                return metadata.Content;
            return null;
        }
        public IMetaDataContent GetMetadataContentByIdOrCode(string metadataId, string metaDataType,bool isMatchMetadataByCode =false)
        {
            return GetMetadataByIdOrCode(metadataId, metaDataType, isMatchMetadataByCode).Content;
        }
        public IMetaData GetMetadataByIdOrCode(string metadataId, string metaDataType, bool isMatchMetadataByCode = false)
        {
            if (isMatchMetadataByCode)
            {
                return MetaDataClientService.GetInstance().GetMetaDataByCode(metadataId, metaDataType);
            }
            else
            {
                return MetaDataClientService.GetInstance().GetMetaData(metadataId);
            }
        }
        public FASMetaData GetFASMetadataByIdOrCode(string metadataId, string metaDataType, bool isMatchMetadataByCode = false)
        {
            FASMetaData fasMetaData = new FASMetaData();
            IMetaData metaData = null;
            if (isMatchMetadataByCode)
            {
                metaData = MetaDataClientService.GetInstance().GetMetaDataByCode(metadataId, metaDataType);
            }
            else
            {
                metaData = MetaDataClientService.GetInstance().GetMetaData(metadataId);
            }
            if (metaData != null)
            {
                fasMetaData.MetaDataContent = metaData.Content;
                if(metaData.MetaDataManageInfos!=null && metaData.MetaDataManageInfos.Count>0)
                    fasMetaData.AppID = metaData.MetaDataManageInfos[0].KeyAppName;
            }
            return fasMetaData;

        }
        public FASMetaData GetActionByCDO(string cdoID, SPI.ActionType actionType, bool isMatchMetadataByCode =false)
        {
            switch (actionType)
            {
                case SPI.ActionType.CDO_ChangeState:
                case SPI.ActionType.CDO_Create:
                case SPI.ActionType.CDO_Delete:
                case SPI.ActionType.CDO_GetByID:
                case SPI.ActionType.CDO_NewInstance:
                case SPI.ActionType.CDO_Update:
                case SPI.ActionType.CDO_BatchDelete:
                case SPI.ActionType.CDO_BatchCreate:
                case SPI.ActionType.CDO_BatchEditUpdate:
                case SPI.ActionType.CDO_BatchUpdate:
                    return GetActionByCDOType(cdoID, actionType, isMatchMetadataByCode);
                default:
                    return null;
            }
        }
        private FASMetaData GetActionByCDOType(string cdoID, SPI.ActionType actionType, bool isMatchMetadataByCode = false)
        {
            var cdoMetadata = GetMetadataContentByIdOrCode(cdoID, ActionRTPConst.MetaDataType_CDO, isMatchMetadataByCode);
            if (cdoMetadata == null)
                throw new FasException(ActionExecuteExceptionCode.ActionMetaDataNotExistError,string.Format(CommonStringClassService.MetadataRTPService_GetActionByCDOType,cdoID));
            var actionViews = ActionRTPLocalCache.GetInstance().GetCDOActionMetadataViews(cdoMetadata);
            if (actionViews == null)
            {
                actionViews = new T.FAS.Runtime.Action.Dao.ActionMetaDataELBDao().GetActionMetaDatasByRelatedMetaDataID(cdoMetadata.MetaDataID);
                var actionViewsCache = ActionRTPLocalCache.GetInstance().GetCDOActionMetadataViews(cdoMetadata);
                if (actionViewsCache == null)
                    ActionRTPLocalCache.GetInstance().AddActionViewCache(cdoMetadata,actionViews);
            }
            if (actionViews != null && actionViews.Count > 0)
            {
                ActionMetaDataView targetActionMetadata = null;
                bool isNeedDependencyMetadata = false;
                List<ActionMetaDataView> dependencyActionMetadatas = null;
                var actionTypeName = "";
                switch (actionType)
                {
                    case SPI.ActionType.CDO_Create:
                        {
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("create", StringComparison.OrdinalIgnoreCase));
                            actionTypeName = "新增";
                            break;
                        }
                    case SPI.ActionType.CDO_Delete:
                        {
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("delete", StringComparison.OrdinalIgnoreCase));
                            actionTypeName = "删除";
                            break;
                        }
                    case SPI.ActionType.CDO_GetByID:
                        {
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("get", StringComparison.OrdinalIgnoreCase));
                            actionTypeName = "查询";
                            break;
                        }
                    case SPI.ActionType.CDO_Update:
                        {
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("update", StringComparison.OrdinalIgnoreCase));
                            actionTypeName = "更新";
                            break;
                        }
                    case SPI.ActionType.CDO_BatchEditUpdate:
                        {
                            isNeedDependencyMetadata = true;
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("batchupdate", StringComparison.OrdinalIgnoreCase));
                            dependencyActionMetadatas = new List<ActionMetaDataView>();
                            var updateAction = actionViews.Find(x=>x.Code.StartsWith("update", StringComparison.OrdinalIgnoreCase));
                            if (updateAction != null)
                            {
                                updateAction.ActionMetaDataViewTag = "update";
                                dependencyActionMetadatas.Add(updateAction);
                            }
                            var deleteAction = actionViews.Find(x=>x.Code.StartsWith("delete",StringComparison.OrdinalIgnoreCase));
                            if (deleteAction != null)
                            {
                                deleteAction.ActionMetaDataViewTag = "delete";
                                dependencyActionMetadatas.Add(deleteAction);
                            }
                            var addAction = actionViews.Find(x=>x.Code.StartsWith("create", StringComparison.OrdinalIgnoreCase));
                            if (addAction != null)
                            {
                                addAction.ActionMetaDataViewTag = "add";
                                dependencyActionMetadatas.Add(addAction);
                            }
                            actionTypeName = "批量更新";
                            break;
                        }
                    case SPI.ActionType.CDO_BatchDelete:
                        {
                            isNeedDependencyMetadata = true;
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("batchdelete", StringComparison.OrdinalIgnoreCase));
                            dependencyActionMetadatas = new List<ActionMetaDataView>();
                            var deleteAction = actionViews.Find(x => x.Code.StartsWith("delete", StringComparison.OrdinalIgnoreCase));
                            if(deleteAction!=null)
                                deleteAction.ActionMetaDataViewTag = "delete";
                            dependencyActionMetadatas.Add(deleteAction);
                            actionTypeName = "批量删除";
                            break;
                        }
                    case SPI.ActionType.CDO_BatchCreate:
                        {
                            isNeedDependencyMetadata = true;
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("batchcreate", StringComparison.OrdinalIgnoreCase));
                            dependencyActionMetadatas = new List<ActionMetaDataView>();
                            //var deleteAction = actionViews.Find(x => x.Code.StartsWith("delete", StringComparison.OrdinalIgnoreCase));
                            //if (deleteAction != null)
                            //    deleteAction.ActionMetaDataViewTag = "delete";
                            //dependencyActionMetadatas.Add(deleteAction);
                            var createAction = actionViews.Find(x => x.Code.StartsWith("create", StringComparison.OrdinalIgnoreCase));
                            if (createAction != null)
                                createAction.ActionMetaDataViewTag = "create";
                            dependencyActionMetadatas.Add(createAction);
                            actionTypeName = "批量创建";
                            break;
                        }
                    case SPI.ActionType.CDO_BatchUpdate:
                        {
                            isNeedDependencyMetadata = true;
                            targetActionMetadata = actionViews.Find(x => x.Code.StartsWith("batchupdate", StringComparison.OrdinalIgnoreCase));
                            dependencyActionMetadatas = new List<ActionMetaDataView>();
                            var updateAction = actionViews.Find(x => x.Code.StartsWith("update", StringComparison.OrdinalIgnoreCase));
                            if (updateAction != null)
                                updateAction.ActionMetaDataViewTag = "update";
                            dependencyActionMetadatas.Add(updateAction);
                            actionTypeName = "批量更新";
                            break;
                        }
                    default:
                        throw new FasException(ActionExecuteExceptionCode.ActionMetaDataNotExistError, string.Format(CommonStringClassService.MetadataRTPService_GetActionByCDOType1,actionType));
                }
                if (targetActionMetadata != null)
                {
                    if (isNeedDependencyMetadata && dependencyActionMetadatas == null && dependencyActionMetadatas.Count<=0)
                    {
                        throw new FasException(ActionExecuteExceptionCode.ActionMetaDataNotExistError, string.Format(CommonStringClassService.MetadataRTPService_GetActionByCDOType2,cdoMetadata.MetaDataCode,actionTypeName));
                    }
                    var targetMetadata = GetMetadata(targetActionMetadata.ID, SPI.ActionType.Action);
                    if (targetMetadata != null && isNeedDependencyMetadata && dependencyActionMetadatas!=null && dependencyActionMetadatas.Count>0)
                    {
                        targetMetadata.DependencyMetadatas = new List<FASMetaData>();
                        dependencyActionMetadatas.ForEach(d=>
                        {
                            var md = GetMetadata(d.ID, SPI.ActionType.Action);
                            if (md != null)
                            {
                                md.FASMetaDataTag = d.ActionMetaDataViewTag;
                                targetMetadata.DependencyMetadatas.Add(md);
                            }
                        });
                    }
                    return targetMetadata;
                }
                else
                    throw new FasException(ActionExecuteExceptionCode.ActionMetaDataNotExistError, string.Format(CommonStringClassService.MetadataRTPService_GetActionByCDOType3,cdoMetadata.MetaDataCode,actionTypeName));
            }
            return null;
        }
        public IMetaDataContent GetMetadata(string metadataId, ref SPI.ActionType actionType)
        {
            var metadata = MetaDataClientService.GetInstance().GetMetaDataContent(metadataId);
            if (metadata.MetaData.MetaTypeID.Equals("action", StringComparison.OrdinalIgnoreCase))
                actionType = SPI.ActionType.Action;
            else
                actionType = SPI.ActionType.DQ;
            return metadata;
        }
    }
}
